package rtda

import (
	"lesson01/rtda/heap"
	"math"
)

//操作数栈

type OperandStack struct {
	size  uint
	slots []Slot
}

func newOperandStack(maxStack uint) *OperandStack {
	if maxStack > 0 {
		return &OperandStack{
			slots: make([]Slot, maxStack),
		}
	}
	return nil
}

func (e *OperandStack) PushInt(val int32) {
	e.slots[e.size].num = val
	e.size++
}

func (e *OperandStack) PopInt() int32 {
	e.size--
	return e.slots[e.size].num
}

func (e *OperandStack) PushFloat(val float32) {
	bits := math.Float32bits(val)
	e.slots[e.size].num = int32(bits)
	e.size++
}

func (e *OperandStack) PopFloat() float32 {
	e.size--
	bits := uint32(e.slots[e.size].num)
	return math.Float32frombits(bits)
}

func (e *OperandStack) PushLong(val int64) {
	e.slots[e.size].num = int32(val)
	e.slots[e.size+1].num = int32(val >> 32)
	e.size += 2
}
func (e *OperandStack) PopLong() int64 {
	e.size -= 2
	low := uint32(e.slots[e.size].num)
	high := uint32(e.slots[e.size+1].num)
	return int64(high)<<32 | int64(low)
}

func (e *OperandStack) PushDouble(val float64) {
	bits := math.Float64bits(val)
	e.PushLong(int64(bits))
}
func (e *OperandStack) PopDouble() float64 {
	bits := uint64(e.PopLong())
	return math.Float64frombits(bits)
}

func (e *OperandStack) PushRef(ref *heap.Object) {
	e.slots[e.size].ref = ref
	e.size++
}
func (e *OperandStack) PopRef() *heap.Object {
	e.size--
	ref := e.slots[e.size].ref
	e.slots[e.size].ref = nil
	return ref
}

func (e *OperandStack) PushSlot(slot Slot) {
	e.slots[e.size] = slot
	e.size++
}

func (e *OperandStack) PopSlot() Slot {
	e.size--
	return e.slots[e.size]
}

// GetRefFromTop  该方法返回距离操作数栈顶n个单元格的引用变量。比如
// GetRefFromTop（0）返回操作数栈顶引用，GetRefFromTop（1）返回从
// 栈顶开始的倒数第二个引用
func (e *OperandStack) GetRefFromTop(n uint) *heap.Object {
	return e.slots[e.size-1-n].ref
}

func (e *OperandStack) PushBoolean(val bool) {
	if val {
		e.PushInt(1)
	} else {
		e.PushInt(0)
	}
}

func (e *OperandStack) PopBoolean() bool {
	return e.PopInt() == 1
}
